package cn.jbt.api.admin.service.impl;

import cn.jbt.api.admin.entity.QXxlJobLog;
import cn.jbt.api.admin.entity.XxlJobLog;
import cn.jbt.api.admin.service.ISysConfigService;
import cn.jbt.api.admin.service.IXxlJobLogService;
import cn.jbt.api.admin.util.XxlJobUtil;
import cn.jbt.common.PageQryParam;
import cn.jbt.common.PageQryResult;
import cn.jbt.config.XxlJobConfig;
import com.alibaba.fastjson2.JSONObject;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import com.querydsl.jpa.impl.JPAQueryFactory;
import groovy.util.logging.Slf4j;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.Optional;

@Service
@AllArgsConstructor
@Slf4j
public class XxlJobLogServiceImpl implements IXxlJobLogService {

    private static final Logger log = LoggerFactory.getLogger(XxlJobLogServiceImpl.class);
    private final JPAQueryFactory jpaQueryFactory;
    private final ISysConfigService iSysConfigService;

    @Override
    public PageQryResult<XxlJobLog> getAllByPage(PageQryParam<XxlJobLog> pageQryParam) {
        XxlJobLog qParam = pageQryParam.getParam();
        QXxlJobLog qXxlJobLog = QXxlJobLog.xxlJobLog;

        Predicate predicate = qXxlJobLog.isNotNull().or(qXxlJobLog.isNull());
        if (null != qParam) {
            if (null != qParam.getJobGroup()) {
                predicate = ExpressionUtils.and(predicate,
                        qXxlJobLog.jobGroup.eq(qParam.getJobGroup()));
            }
            if (null != qParam.getJobId()) {
                predicate = ExpressionUtils.and(predicate,
                        qXxlJobLog.jobId.eq(qParam.getJobId()));
            }
            if (qParam.getLogStatus().equals(1)) {  // 成功
                predicate = ExpressionUtils.and(predicate,
                        qXxlJobLog.handleCode.eq(200));
            }
            if (qParam.getLogStatus().equals(2)) {  // 失败
                predicate = ExpressionUtils.and(predicate,
                        ExpressionUtils.or(qXxlJobLog.triggerCode.notIn(0, 200), qXxlJobLog.handleCode.notIn(0, 200)));
            }
            if (qParam.getLogStatus().equals(3)) {  // 处理中
                predicate = ExpressionUtils.and(predicate,
                        qXxlJobLog.triggerCode.eq(200));
                predicate = ExpressionUtils.and(predicate,
                        qXxlJobLog.handleCode.eq(0));
            }
            if (null != qParam.getCreateTimeStart()) {
                predicate = ExpressionUtils.and(predicate,
                        qXxlJobLog.triggerTime.goe(qParam.getCreateTimeStart()));
            }
            if (null != qParam.getCreateTimeEnd()) {
                predicate = ExpressionUtils.and(predicate,
                        qXxlJobLog.triggerTime.loe(qParam.getCreateTimeEnd()));
            }
        }

        List<XxlJobLog> list = jpaQueryFactory.select(qXxlJobLog)
                .from(qXxlJobLog)
                .where(predicate)
                .orderBy(qXxlJobLog.id.desc())
                .offset((pageQryParam.getPage() - 1) * pageQryParam.getSize())
                .limit(pageQryParam.getSize())
                .fetch();

        long total = Optional.ofNullable(jpaQueryFactory.select(qXxlJobLog.id.count())
                .from(qXxlJobLog)
                .where(predicate)
                .fetchOne()
        ).orElse(0L);

        return new PageQryResult<>(list, total);
    }

    @Override
    public void kill(int id) {
        XxlJobConfig xxlJobConfig = (XxlJobConfig) iSysConfigService.getConfig("XxlJob");

        XxlJobUtil xxlJobUtil = new XxlJobUtil()
                .setXxlJobConfig(xxlJobConfig);

        List<String> cookies = xxlJobUtil.getCookiesByLogin();
        log.info("cookies: {}", cookies);

        RestTemplate restTemplate = new RestTemplate();
        // headers
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.put(HttpHeaders.COOKIE, cookies);
        // form variables
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        map.add("id", id);
        // request
        HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(map, headers);
        // response
        ResponseEntity<String> response = restTemplate.postForEntity(
                String.format("%s/joblog/kill", xxlJobConfig.getAdminAddresses()),
                request, String.class);
        if (!response.getStatusCode().equals(HttpStatus.OK)) {
            throw new RuntimeException("请求错误：" + response.getStatusCode());
        }

        log.info("getBody: {}", response.getBody());
        JSONObject result = JSONObject.parseObject(response.getBody());
        assert result != null;

        if (result.getInteger("code") != 200) {
            throw new RuntimeException(result.getString("msg"));
        }
    }

    /**
     * <h2>执行日志</h2>
     */
    @Override
    public JSONObject execLog(int id) {
        XxlJobConfig xxlJobConfig = (XxlJobConfig) iSysConfigService.getConfig("XxlJob");

        XxlJobUtil xxlJobUtil = new XxlJobUtil()
                .setXxlJobConfig(xxlJobConfig);

        List<String> cookies = xxlJobUtil.getCookiesByLogin();

        RestTemplate restTemplate = new RestTemplate();
        // headers
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.put(HttpHeaders.COOKIE, cookies);
        // form variables
        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        map.add("logId", id);
        map.add("fromLineNum", 1);
        // request
        HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(map, headers);
        // response
        ResponseEntity<String> response = restTemplate.postForEntity(
                String.format("%s/joblog/logDetailCat", xxlJobConfig.getAdminAddresses()),
                request, String.class);
        if (!response.getStatusCode().equals(HttpStatus.OK)) {
            throw new RuntimeException("请求错误：" + response.getStatusCode());
        }

        JSONObject result = JSONObject.parseObject(response.getBody());
        assert result != null;

        if (result.getInteger("code").equals(500)) {
            return new JSONObject().fluentPut("logContent", result.toJSONString());
        }

        if (result.getInteger("code") != 200) {
            throw new RuntimeException(result.getString("msg"));
        }
        return result.getJSONObject("content");
    }

}
